package xin.marcher.module.inventory.repository;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import xin.marcher.module.common.enums.inventory.InventoryDeductionTypeEnum;
import xin.marcher.module.common.enums.inventory.InventoryExceptionCode;
import xin.marcher.module.common.enums.inventory.TemplateEnum;
import xin.marcher.module.common.exception.BaseBizException;
import xin.marcher.module.common.utils.SnowflakeIdWorker;
import xin.marcher.module.inventory.converter.InventoryConverter;
import xin.marcher.module.inventory.domain.bo.*;
import xin.marcher.module.inventory.domain.entity.*;
import xin.marcher.module.inventory.domain.request.InventorBucketRequest;
import xin.marcher.module.inventory.mapper.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 库存相关 资源类
 *
 * 
 */
@Repository
public class InventoryRepository {

    @Resource
    private InventoryBucketOperateMapper inventoryBucketOperateMapper;

    @Resource
    private InventoryOperateFailMapper inventoryOperateFailMapper;

    @Resource
    private InventoryBucketConfigMapper inventoryBucketConfigMapper;

    @Resource
    private InventoryAllotDetailMapper inventoryAllotDetailMapper;

    @Resource
    private InventoryDetailMapper inventoryDetailMapper;

    @Resource
    private InventoryConverter inventoryConverter;

    /**
     * 获取默认的库存分配模板
     *
     * @param templateId 模板id
     * @return
     */
    public InventoryBucketConfigDO getInventoryBucketConfig(Long templateId) {
        LambdaQueryWrapper<InventoryBucketConfigDO> queryWrapper = Wrappers.lambdaQuery();
        // 没有选择模板，获取默认的配置模板
        if (Objects.isNull(templateId)) {
            queryWrapper.eq(InventoryBucketConfigDO::getIsDefault, TemplateEnum.DEFAULT.getCode());
        } else {
            queryWrapper.eq(InventoryBucketConfigDO::getId, templateId);
        }
        return inventoryBucketConfigMapper.selectOne(queryWrapper);
    }

    /**
     * 存储每次新增库存的申请记录
     *
     * @param request
     */
    public void saveInventoryAllotDetail(InventorBucketRequest request) {
        InventoryAllotDetailDO inventoryAllotDetailDO = inventoryConverter.converterDO(request);
        inventoryAllotDetailDO.initCommon();
        int count = inventoryAllotDetailMapper.insert(inventoryAllotDetailDO);

        if (count <= 0) {
            throw new BaseBizException(InventoryExceptionCode.INVENTORY_SQL);
        }
    }

    /**
     * 保存库存扣减的明细
     *
     * @param inventoryDetail
     */
    public void saveInventoryDetail(InventoryDetail inventoryDetail, Integer deductionType) throws DuplicateKeyException {
        InventoryDeductionDetailDO inventoryDeductionDetailDO = inventoryConverter.converterDO(inventoryDetail);
        inventoryDeductionDetailDO.setDeductionType(deductionType);
        inventoryDeductionDetailDO.initCommon();
        int count = inventoryDetailMapper.insert(inventoryDeductionDetailDO);
        if (count <= 0) {
            throw new BaseBizException(InventoryExceptionCode.INVENTORY_SQL);
        }
    }

    /**
     * 批量保存库存扣减的明细
     *
     * @param inventoryDetailList
     */
    public void saveInventoryDetailList(List<InventoryDetail> inventoryDetailList, Integer deductionType) throws DuplicateKeyException {
        List<InventoryDeductionDetailDO> inventoryDeductionDetailDOList = inventoryConverter.converterDOList(inventoryDetailList);
        //对象转换赋值
        for (InventoryDeductionDetailDO inventoryDeductionDetailDO : inventoryDeductionDetailDOList) {
            inventoryDeductionDetailDO.setDeductionType(deductionType);
            inventoryDeductionDetailDO.initCommon();
        }

        int count = inventoryDetailMapper.insertBatch(inventoryDeductionDetailDOList);
        if (count <= 0) {
            throw new BaseBizException(InventoryExceptionCode.INVENTORY_SQL);
        }
    }

    /**
     * 根据订单号查询 库存扣减明细
     *
     * @param orderId
     * @return
     */
    public InventoryDetail getInventoryDetail(String orderId) {
        LambdaQueryWrapper<InventoryDeductionDetailDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(InventoryDeductionDetailDO::getOrderId, orderId);
        queryWrapper.eq(InventoryDeductionDetailDO::getDeductionType, InventoryDeductionTypeEnum.INVENTORY_DETAIL_DEDUCTIONS_TYPE.getCode());
        InventoryDeductionDetailDO inventoryDeductionDetailDO = inventoryDetailMapper.selectOne(queryWrapper);

        return inventoryConverter.converter(inventoryDeductionDetailDO);
    }

    /**
     * 获取扣减库存对应的已退明细
     *
     * @param orderId
     * @return
     */
    public List<InventoryDetail> queryRefundInventoryDetailList(String orderId) {
        LambdaQueryWrapper<InventoryDeductionDetailDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(InventoryDeductionDetailDO::getOrderId, orderId);
        queryWrapper.eq(InventoryDeductionDetailDO::getDeductionType, InventoryDeductionTypeEnum.INVENTORY_DETAIL_REFUND_TYPE.getCode());

        List<InventoryDeductionDetailDO> inventoryDeductionDetailDOS = inventoryDetailMapper.selectList(queryWrapper);

        return inventoryConverter.converterList(inventoryDeductionDetailDOS);
    }

    /**
     * 保存分桶操作信息
     *
     * @param operateId         操作id
     * @param bucketLocalCache  变更之后的元数据信息
     * @param operateType       操作类型
     * @param bucketCacheBOList 变动的分桶列表
     * @param inventoryNum      变动的库存数量
     */
    public void saveBucketDetail(String operateId, BucketLocalCache bucketLocalCache, Integer operateType,
                                 List<BucketCacheBO> bucketCacheBOList, Integer inventoryNum) {
        // 变动的分桶为空，则不必要保存
        if (CollectionUtils.isEmpty(bucketCacheBOList)) {
            return;
        }

        if (!StringUtils.hasLength(operateId)) {
            operateId = SnowflakeIdWorker.getCode();
        }

        InventoryBucketOperateDO inventoryBucketOperateDO = InventoryBucketOperateDO.builder()
                .operateId(operateId)
                .sellerId(bucketLocalCache.getSellerId())
                .skuId(bucketLocalCache.getSkuId())
                .bucket(JSON.toJSONString(bucketCacheBOList))
                .operateType(operateType)
                .feature(JSON.toJSONString(bucketLocalCache))
                .inventoryNum(inventoryNum)
                .build();

        int count = inventoryBucketOperateMapper.insert(inventoryBucketOperateDO);

        if (count <= 0) {
            throw new BaseBizException(InventoryExceptionCode.INVENTORY_SQL);
        }
    }

    /**
     * 待执行的分桶操作任务总数
     *
     * @return
     */
    public Integer countBucketOperate(Integer operateStatus) {
        LambdaQueryWrapper<InventoryBucketOperateDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(InventoryBucketOperateDO::getOperateStatus, operateStatus);
        return inventoryBucketOperateMapper.selectCount(queryWrapper);
    }

    /**
     * 分页查询待执行的分桶操作任务
     *
     * @param operateStatus
     * @param page
     * @param size
     * @return
     */
    public List<InventoryBucketOperateBO> queryBucketOperateList(Integer operateStatus, int page, int size) {
        List<InventoryBucketOperateDO> inventoryBucketOperateDOS =
                inventoryBucketOperateMapper.queryBucketOperateList(operateStatus, (page - 1) * size, size);
        return inventoryConverter.converter(inventoryBucketOperateDOS);
    }

    /**
     * 删除分桶操作任务
     *
     * @param id
     */
    public void deleteBucketOperate(Long id) {
        inventoryBucketOperateMapper.deleteById(id);
    }

    /**
     * 批量删除分桶操作任务
     *
     * @param ids
     */
    public void deleteBatchBucketOperate(List<Long> ids) {
        inventoryBucketOperateMapper.deleteBatchIds(ids);
    }

    /**
     * 批量修改分桶操作任务状态
     *
     * @param ids
     * @param operateStatus
     */
    public void bucketOperateSuccess(List<Long> ids, Integer operateStatus) {
        inventoryBucketOperateMapper.updateBatchStatus(ids, operateStatus);
    }

    public void saveFailOperate(String operateId, String failType, String bucketNo, Integer inventoryNum) {
        InventoryOperateFailDO inventoryOperateFailDO = InventoryOperateFailDO.builder()
                .operateId(operateId)
                .failType(failType)
                .bucketNo(bucketNo)
                .inventoryNum(inventoryNum)
                .build();
        inventoryOperateFailMapper.insert(inventoryOperateFailDO);
    }

    public List<InventoryOperateFailBO> queryFailOperateList(String operateId) {
        LambdaQueryWrapper<InventoryOperateFailDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(InventoryOperateFailDO::getOperateId, operateId);
        List<InventoryOperateFailBO> inventoryOperateFailBOS = inventoryConverter.converterOperateFailList(inventoryOperateFailMapper.selectList(queryWrapper));
        if (Objects.isNull(inventoryOperateFailBOS)) {
            return Lists.newArrayList();
        }
        return inventoryOperateFailBOS;
    }

    public void deleteBatchOperateFail(List<InventoryOperateFailBO> inventoryOperateFailBOS) {
        List<Long> ids = inventoryOperateFailBOS.stream().map(InventoryOperateFailBO::getId).collect(Collectors.toList());
        inventoryOperateFailMapper.deleteBatchIds(ids);
    }
}
